package net.mhelvens.deltaprofiles;

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.util.LongSparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

final public class ConditionType extends DBEntity {
	
	////////// Public Methods //////////////////////////////////////////////////
	
    ///// URIs /////
    
    public Uri uri            () { return uri_base().buildUpon().appendPath("/"+id())      .build(); }
    public Uri uri_source     () { return uri()     .buildUpon().appendPath("/source")     .build(); }
    public Uri uri_listed     () { return uri()     .buildUpon().appendPath("/listed")     .build(); }
    public Uri uri_description() { return uri()     .buildUpon().appendPath("/description").build(); }
    
    ///// Mutators /////
    
	public ConditionType setSource(String source) {
		mSource = source;
		
    	ContentValues values = new ContentValues();
    	values.put(KEY_source, mSource);
    	DeltaProfilesDB.get().db().update(
    		TABLE_main, values, KEY_id+" = "+id(), null
    	);
		
		broadcast(ACTION_BROADCAST_MODIFY, uri_source());
		
		return this;
	}

	public ConditionType setListed(Boolean listed) {
		mListed = listed;
		
    	ContentValues values = new ContentValues();
    	values.put(KEY_listed, mListed);
    	DeltaProfilesDB.get().db().update(
    		TABLE_main, values, KEY_id+" = "+id(), null
    	);
		
		broadcast(ACTION_BROADCAST_MODIFY, uri_listed());
		
		return this;
	}

	public ConditionType setDescription(String description) {
		mDescription = description;
		
    	ContentValues values = new ContentValues();
    	values.put(KEY_description, mDescription);
    	DeltaProfilesDB.get().db().update(
    		TABLE_main, values, KEY_id+" = "+id(), null
    	);
		
		broadcast(ACTION_BROADCAST_MODIFY, uri_description());
		
		return this;
	}
	
	public void delete() {
		assert !isDeleted();
		
		DeltaProfilesDB.get().db().delete(
			TABLE_main, KEY_id+" = "+id(), null
		);
		
		mCache.delete( id() );
		
		mDeleted = true;
		
		broadcast(ACTION_BROADCAST_DELETE, uri());
	}

	///// Accessors /////
	
	public boolean isDeleted() {
		return mDeleted;
	}
	
	public long id() {
		assert !isDeleted();
		
		return mID;
	}
	
	public String source() {
		assert !isDeleted();
		
		refresh();
		return mSource;
	}
	
	public Uri sourceUri() {
		return new Uri.Builder().path(source()).build();
	}
	
	public Boolean listed() {
		assert !isDeleted();
		
		refresh();
		return mListed;
	}
	
	public String description() {
		assert !isDeleted();
		
		refresh();
		return mDescription;
	}

	////////// Private Fields //////////////////////////////////////////////////
	
	///// Bookkeeping /////
	
	private boolean mDeleted = false;
	private boolean mValid   = false;
	
	///// Unique Database ID /////
	
	private long mID;
	
	///// Data-items and Defaults /////

	private String  mSource      = "";
	private Boolean mListed      = false;
	private String  mDescription = "";
	
	////////// Private Methods /////////////////////////////////////////////////
	
	///// Constructors /////
	
	private ConditionType() {
    	mID = DeltaProfilesDB.get().db()
    		.insertOrThrow(TABLE_main, null, valuesForDB());
    	
    	setValid();
    	
		broadcast(ACTION_BROADCAST_ADD, uri());
	}
	
	private ConditionType(long id) {
		mID = id;
		
		setInvalid();
	}
	
	///// Utility Methods /////
	
	private ContentValues valuesForDB() {
		ContentValues result = new ContentValues();
		result.put( KEY_source     , mSource      );
		result.put( KEY_listed     , mListed      );
		result.put( KEY_description, mDescription );
		return result;
	}

	private void setValuesFromDB(Cursor c) {
		assert !c.isBeforeFirst() && !c.isAfterLast();

		mSource      = c.getString( c.getColumnIndex(KEY_source     ) );
		mListed      = c.getShort ( c.getColumnIndex(KEY_listed     ) ) != 0;
		mDescription = c.getString( c.getColumnIndex(KEY_description) );
	}
	
	private void broadcast(String action, Uri uri) { broadcast(action, uri, null); }
	private void broadcast(String action, Uri uri, Bundle extras) {
		LocalBroadcastManager.getInstance(mContext).sendBroadcast(
			new Intent(action, uri()).putExtra("id", id())
		);
	}
	
	private void setInvalid() { mValid = false; }
	private void setValid  () { mValid = true ; }
	
	private void refresh() { refresh(null); }
	private void refresh(Cursor c) {
		assert !isDeleted();
		if (!mValid) {
			// is a positioned cursor supplied already? otherwise, perform query
			if (c == null) {
				c = DeltaProfilesDB.get().db().query(
					TABLE_main, null, KEY_id+" = "+id(),
					null, null, null, null);
				c.moveToFirst();
			}
			
			setValuesFromDB(c);
			
			setValid();
		}
	}
	
	
	////////// Static //////////////////////////////////////////////////////////
	
	///// Public Methods /////
	
	static public Uri uri_base() { return new Uri.Builder().path("/condition-types").build(); }
	
	static public void setContext(Context context) {
		mContext = context;
	}
	
	static public long count() {
		Cursor c = DeltaProfilesDB.get().db()
			.rawQuery("SELECT COUNT(*) FROM "+TABLE_main, null);
		c.moveToFirst();
		return c.getLong(0);
	}
	
    static public ConditionType getNew() {
    	ConditionType result = new ConditionType();
    	mCache.put(result.id(), result);
    	return result;
    }
    
    static public Adapter all() {
    	return new Adapter(
    		DeltaProfilesDB.get().db().query(
    			TABLE_main, null, null,
    			null, null, null, null
    		)
    	);
    }
    
    static public Adapter allListed() {
    	return new Adapter(
    		DeltaProfilesDB.get().db().query(
    			TABLE_main, null, KEY_listed+" = 1",
    			null, null, null, null
    		)
    	);
    }
    
    static public ConditionType get(long id) { return get(id, null); }
	
    
	///// Private Fields /////
    
	static private Context                        mContext;
	static private LongSparseArray<ConditionType> mCache = new LongSparseArray<ConditionType>();
	
	
	///// Broadcast Actions /////
	
	static public final String ACTION_BROADCAST_ADD    = "net.mhelvens.deltaprofiles.ConditionType.ACTION_BROADCAST_ADD";
	static public final String ACTION_BROADCAST_MODIFY = "net.mhelvens.deltaprofiles.ConditionType.ACTION_BROADCAST_MODIFY";
	static public final String ACTION_BROADCAST_DELETE = "net.mhelvens.deltaprofiles.ConditionType.ACTION_BROADCAST_DELETE";
	
	
	///// Database Tables, Views and Keys /////
	
    //=====================================================================
    static private final String TABLE_main = "condition_types";
    //---------------------------------------------------------------------
	static private final String KEY_id          = BaseColumns._ID;
    static private final String KEY_source      = "source";
    static private final String KEY_listed      = "listed";
    static private final String KEY_description = "description";
    //=====================================================================

    
	///// Private Utility Methods /////
	
    static private ConditionType get(long id, Cursor possibleCursor) {
    	if (!isCached(id))
    		mCache.put(id, new ConditionType(id));
    	
    	if (possibleCursor != null)
    		mCache.get(id).refresh(possibleCursor);
    	
    	return mCache.get(id);
    }
	
    static private boolean isCached(long id) {
    	return mCache.get(id, null) != null;
    }
    
    
    ///// Public Adapter /////
	
	static public class Adapter extends BaseAdapter {
		
		///// Private Fields /////

		private Cursor mCursor;
		
		///// Private Methods /////
		
		private Adapter(Cursor cursor) {
			mCursor = cursor;
		}

		///// Public Methods /////
		
		@Override
		public int getCount() {
			return mCursor.getCount();
		}
		
		@Override
		public ConditionType getItem(int position) {
			mCursor.moveToPosition(position);
			
			long id = mCursor.getLong(mCursor.getColumnIndex(ConditionType.KEY_id));
			
	    	return get(id, mCursor);
		}
		
		@Override
		public long getItemId(int position) {
			return getItem(position).id();
		}
		
		@Override
		public View getView(final int position, View view, ViewGroup parent) {
			final ConditionType ctype = getItem(position);
			
			// possibly reuse view, otherwise inflate new one
			//
			if (view == null) {
				view = ((LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
					.inflate(R.layout.condition_list_item, parent, false);
			}
			
			// Description
			//
			TextView descriptionView = (TextView) view.findViewById(R.id.description);
			descriptionView.setText(ctype.description());
			
			return view;
		}
		
	} ///// Rule.Adapter
}
